#include "bindings/bindings_file_asset.h"
#include "helpers/canvas_render_objects.h"
#include "helpers/factories.h"
#include "helpers/image_decode.h"
#include <vector>

namespace ohos_rive {

using namespace rive;

// 辅助函数：获取字节数组数据
bool OhosFileAsset::GetBytesFromArray(napi_env env,
                                      napi_value array,
                                      rive::SimpleArray<uint8_t> &bytes,
                                      bool useRawData)
{
    bool isTypedArray;
    napi_is_typedarray(env, array, &isTypedArray);

    if (isTypedArray) {
        napi_typedarray_type type;
        size_t length;
        void *data;
        napi_value buffer;
        size_t byteOffset;

        napi_status status = napi_get_typedarray_info(env, array, &type, &length, &data, &buffer, &byteOffset);
        if (status != napi_ok || type != napi_uint8_array) {
            return false;
        }

        if (useRawData) {
            // 直接使用原始数据指针（用于 decode，允许音频窃取字节）
            bytes = rive::SimpleArray<uint8_t>(reinterpret_cast<uint8_t *>(data), length);
        } else {
            // 创建数据副本（用于创建 RenderImage 等）
            std::vector<uint8_t> tempBytes(length);
            memcpy(tempBytes.data(), data, length);
            bytes = rive::SimpleArray<uint8_t>(tempBytes.data(), length);
        }
        return true;
    } else {
        // 处理普通数组（总是创建副本）
        uint32_t length;
        napi_get_array_length(env, array, &length);

        std::vector<uint8_t> tempBytes(length);
        for (uint32_t i = 0; i < length; i++) {
            napi_value element;
            int32_t value;
            napi_get_element(env, array, i, &element);
            napi_get_value_int32(env, element, &value);
            tempBytes[i] = static_cast<uint8_t>(value);
        }

        bytes = rive::SimpleArray<uint8_t>(tempBytes.data(), length);
        return true;
    }
}

// FileAsset 基础方法
napi_value OhosFileAsset::GetName(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value argv[1];
    napi_value thisArg;

    napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr);
    if (argc < 1) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    auto *fileAsset = GetNativePtr<rive::FileAsset>(env, argv[0]);
    if (!fileAsset) {
        LOGE("Invalid FileAsset pointer");
        return nullptr;
    }

    napi_value result;
    napi_create_string_utf8(env, fileAsset->name().c_str(), NAPI_AUTO_LENGTH, &result);
    return result;
}

napi_value OhosFileAsset::GetUniqueFilename(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value argv[1];
    napi_value thisArg;

    napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr);
    if (argc < 1) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    auto *fileAsset = GetNativePtr<rive::FileAsset>(env, argv[0]);
    if (!fileAsset) {
        LOGE("Invalid FileAsset pointer");
        return nullptr;
    }

    napi_value result;
    napi_create_string_utf8(env, fileAsset->uniqueFilename().c_str(), NAPI_AUTO_LENGTH, &result);
    return result;
}

napi_value OhosFileAsset::Decode(napi_env env, napi_callback_info info)
{
    size_t argc = 3;
    napi_value argv[3];
    napi_value thisArg;

    napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr);
    if (status != napi_ok || argc < 3) {
        LOGE("Failed to get callback info or wrong number of arguments");
        return nullptr;
    }

    auto *fileAsset = GetNativePtr<rive::FileAsset>(env, argv[0]);
    if (!fileAsset) {
        LOGE("Invalid FileAsset pointer");
        return nullptr;
    }

    // 获取渲染器类型
    int32_t rendererTypeIndex;
    napi_get_value_int32(env, argv[2], &rendererTypeIndex);
    auto rendererType = static_cast<RendererType>(rendererTypeIndex);

    // 获取字节数据
    rive::SimpleArray<uint8_t> bytes;
    if (!GetBytesFromArray(env, argv[1], bytes, true)) {
        LOGE("Failed to get byte array");
        return nullptr;
    }

    auto *fileFactory = GetFactory(rendererType);
    bool result = fileAsset->decode(bytes, fileFactory);

    napi_value jsResult;
    napi_get_boolean(env, result, &jsResult);
    return jsResult;
}

napi_value OhosFileAsset::GetCDNUrl(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value argv[1];
    napi_value thisArg;

    napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr);
    if (argc < 1) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    auto *fileAsset = GetNativePtr<rive::FileAsset>(env, argv[0]);
    if (!fileAsset) {
        LOGE("Invalid FileAsset pointer");
        return nullptr;
    }

    napi_value result;
    auto uuid = fileAsset->cdnUuidStr();
    if (uuid.empty()) {
        napi_create_string_utf8(env, "", NAPI_AUTO_LENGTH, &result);
        return result;
    }

    auto cdnUrl = fileAsset->cdnBaseUrl();
    auto lastChar = cdnUrl.back();
    if (lastChar != '/') {
        cdnUrl += '/';
    }
    cdnUrl += uuid;

    napi_create_string_utf8(env, cdnUrl.c_str(), NAPI_AUTO_LENGTH, &result);
    return result;
}

// ImageAsset 方法
napi_value OhosFileAsset::SetRenderImage(napi_env env, napi_callback_info info)
{
    size_t argc = 2;
    napi_value argv[2];
    napi_value thisArg;

    napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr);
    if (argc < 2) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    auto *imageAsset = GetNativePtr<rive::ImageAsset>(env, argv[0]);
    auto *renderImage = GetNativePtr<rive::RenderImage>(env, argv[1]);

    if (!imageAsset || !renderImage) {
        LOGE("Invalid pointer");
        return nullptr;
    }

    imageAsset->renderImage(rive::ref_rcp(renderImage));

    napi_value result;
    napi_get_undefined(env, &result);
    return result;
}

napi_value OhosFileAsset::GetRenderImage(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value argv[1];
    napi_value thisArg;

    napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr);
    if (argc < 1) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    auto *imageAsset = GetNativePtr<rive::ImageAsset>(env, argv[0]);
    if (!imageAsset) {
        LOGE("Invalid ImageAsset pointer");
        return nullptr;
    }

    auto renderImage = imageAsset->renderImage();
    napi_value result;
    napi_create_int64(env, reinterpret_cast<int64_t>(renderImage), &result);
    return result;
}

napi_value OhosFileAsset::GetImageWidth(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value argv[1];
    napi_value thisArg;

    napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr);
    if (argc < 1) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    auto *imageAsset = GetNativePtr<rive::ImageAsset>(env, argv[0]);
    if (!imageAsset) {
        LOGE("Invalid ImageAsset pointer");
        return nullptr;
    }

    napi_value result;
    napi_create_double(env, imageAsset->width(), &result);
    return result;
}

napi_value OhosFileAsset::GetImageHeight(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value argv[1];
    napi_value thisArg;

    napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr);
    if (argc < 1) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    auto *imageAsset = GetNativePtr<rive::ImageAsset>(env, argv[0]);
    if (!imageAsset) {
        LOGE("Invalid ImageAsset pointer");
        return nullptr;
    }

    napi_value result;
    napi_create_double(env, imageAsset->height(), &result);
    return result;
}

// RenderImage 创建方法
napi_value OhosFileAsset::CreateFromRGBABytes(napi_env env, napi_callback_info info)
{
    size_t argc = 5;
    napi_value argv[5];
    napi_value thisArg;

    napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr);
    if (argc < 5) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    // 获取参数
    rive::SimpleArray<uint8_t> bytes;
    if (!GetBytesFromArray(env, argv[0], bytes, false)) {
        LOGE("Failed to get byte array");
        return nullptr;
    }

    int32_t width, height, rendererTypeIdx;
    bool premultiplied;
    napi_get_value_int32(env, argv[1], &width);
    napi_get_value_int32(env, argv[2], &height);
    napi_get_value_int32(env, argv[3], &rendererTypeIdx);
    napi_get_value_bool(env, argv[4], &premultiplied);

    // 验证参数
    size_t expected = static_cast<size_t>(width) * static_cast<size_t>(height) * 4u;
    if (width <= 0 || height <= 0 || bytes.size() != expected) {
        LOGE("Invalid arguments for RGBABytes");
        return nullptr;
    }

    auto rendererType = static_cast<RendererType>(rendererTypeIdx);
    rive::rcp<rive::RenderImage> renderImage;

    if (rendererType == RendererType::Rive) {
        renderImage = renderImageFromRGBABytesRive(static_cast<uint32_t>(width), static_cast<uint32_t>(height),
                                                   bytes.data(), premultiplied);
    } else {
        renderImage = renderImageFromRGBABytesCanvas(static_cast<uint32_t>(width), static_cast<uint32_t>(height),
                                                     bytes.data(), premultiplied);
    }

    if (!renderImage) {
        LOGE("Failed to create render image");
        return nullptr;
    }

    napi_value result;
    napi_create_int64(env, reinterpret_cast<int64_t>(renderImage.release()), &result);
    return result;
}

// CreateFromARGBInts 实现
napi_value OhosFileAsset::CreateFromARGBInts(napi_env env, napi_callback_info info)
{
    size_t argc = 5;
    napi_value argv[5];
    napi_value thisArg;

    napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr);
    if (argc < 5) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    // 获取像素数组
    napi_typedarray_type arrayType;
    size_t pixelCount;
    void *pixelData;
    napi_value buffer;
    size_t byteOffset;

    napi_status status =
        napi_get_typedarray_info(env, argv[0], &arrayType, &pixelCount, &pixelData, &buffer, &byteOffset);
    if (status != napi_ok || arrayType != napi_uint32_array) {
        LOGE("Expected Uint32Array for pixel data");
        return nullptr;
    }

    // 获取其他参数
    int32_t width, height, rendererTypeIdx;
    bool premultiplied;
    napi_get_value_int32(env, argv[1], &width);
    napi_get_value_int32(env, argv[2], &height);
    napi_get_value_int32(env, argv[3], &rendererTypeIdx);
    napi_get_value_bool(env, argv[4], &premultiplied);

    // 验证参数
    size_t expectedPixels = static_cast<size_t>(width) * static_cast<size_t>(height);
    if (width <= 0 || height <= 0 || pixelCount != expectedPixels) {
        LOGE("Invalid arguments for ARGBInts");
        return nullptr;
    }

    auto rendererType = static_cast<RendererType>(rendererTypeIdx);
    const uint32_t *pixels = reinterpret_cast<const uint32_t *>(pixelData);

    rive::rcp<rive::RenderImage> renderImage;

    if (rendererType == RendererType::Rive) {
        renderImage = ohos_rive::renderImageFromARGBIntsRive(static_cast<uint32_t>(width),
                                                             static_cast<uint32_t>(height), pixels, premultiplied);
    } else {
        renderImage = ohos_rive::renderImageFromARGBIntsCanvas(static_cast<uint32_t>(width),
                                                               static_cast<uint32_t>(height), pixels, premultiplied);
    }

    if (!renderImage) {
        LOGE("Failed to create render image from ARGB ints");
        return nullptr;
    }

    napi_value result;
    napi_create_int64(env, reinterpret_cast<int64_t>(renderImage.release()), &result);
    return result;
}

// CreateFromBitmap 实现
napi_value OhosFileAsset::CreateFromBitmap(napi_env env, napi_callback_info info)
{
    /* 方案一，传递options
    size_t argc = 6;
    napi_value argv[6];
    napi_value thisArg;

    napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr);
    if (argc < 6) {
        LOGE("Wrong number of arguments, expected 6");
        return nullptr;
    }

    // 获取参数
    uint32_t width, height;
    int32_t pixelFormat, alphaType, rendererTypeIdx;
    bool premultiplied;

    // 解析参数
    napi_get_value_uint32(env, argv[0], &width);
    napi_get_value_uint32(env, argv[1], &height);
    napi_get_value_int32(env, argv[2], &pixelFormat);
    napi_get_value_int32(env, argv[3], &alphaType);
    napi_get_value_bool(env, argv[4], &premultiplied);
    napi_get_value_int32(env, argv[5], &rendererTypeIdx);

    auto rendererType = static_cast<RendererType>(rendererTypeIdx);

    // 创建 OH_Pixelmap_InitializationOptions
    OH_Pixelmap_InitializationOptions* options = CreatePixelMapOptions(width, height, pixelFormat, alphaType);
    if (!options) {
        LOGE("Failed to create PixelMap initialization options");
        return nullptr;
    }

    rive::rcp<rive::RenderImage> renderImage;

    if (rendererType == RendererType::Rive) {
        // 使用 Rive 渲染器
        renderImage = ohos_rive::renderImageFromBitmapRive(env, options, premultiplied);
    } else {
        // 使用 Canvas 渲染器
        renderImage = ohos_rive::renderImageFromPixelmapCanvas(options);
    }

    if (!renderImage) {
        LOGE("Failed to create render image from bitmap parameters");
        return nullptr;
    }

    napi_value result;
    napi_create_int64(env, reinterpret_cast<int64_t>(renderImage.release()), &result);
    return result;
    */

    // 方案二，传递pixelmap
    size_t argc = 3;
    napi_value argv[3];
    napi_value thisArg;

    napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr);
    if (argc < 3) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    napi_value pixelMapValue = argv[0];
    int32_t rendererTypeIdx;
    bool premultiplied;
    napi_get_value_int32(env, argv[1], &rendererTypeIdx);
    napi_get_value_bool(env, argv[2], &premultiplied);

    auto rendererType = static_cast<RendererType>(rendererTypeIdx);
    rive::rcp<rive::RenderImage> renderImage;

    if (rendererType == RendererType::Rive) {
        // 使用 Rive 渲染器
        renderImage = ohos_rive::renderImageFromPixelMapRive(env, pixelMapValue, premultiplied);
    } else {
        renderImage = ohos_rive::renderImageFromPixelmapCanvas(env, pixelMapValue);
    }

    if (!renderImage) {
        LOGE("Failed to create render image from bitmap");
        return nullptr;
    }

    napi_value result;
    napi_create_int64(env, reinterpret_cast<int64_t>(renderImage.release()), &result);
    return result;
}

napi_value OhosFileAsset::ReleaseRenderImage(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value argv[1];
    napi_value thisArg;

    napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr);
    if (argc < 1) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    int64_t ptrValue = 0;
    napi_status status = napi_get_value_int64(env, argv[0], &ptrValue);
    if (status != napi_ok || ptrValue == 0 || ptrValue == 0x9) {
        napi_value result;
        napi_get_undefined(env, &result);
        return result;
    }

    // 使用统一的释放机制
    releaseAsset<rive::RenderImage>(ptrValue);

    napi_value result;
    napi_get_undefined(env, &result);
    return result;
}

// FontAsset 方法
napi_value OhosFileAsset::SetFont(napi_env env, napi_callback_info info)
{
    size_t argc = 2;
    napi_value argv[2];
    napi_value thisArg;

    napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr);
    if (argc < 2) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    auto *fontAsset = GetNativePtr<rive::FontAsset>(env, argv[0]);
    auto *font = GetNativePtr<rive::Font>(env, argv[1]);

    if (!fontAsset || !font) {
        LOGE("Invalid pointer");
        return nullptr;
    }

    fontAsset->font(rive::ref_rcp(font));

    napi_value result;
    napi_get_undefined(env, &result);
    return result;
}

napi_value OhosFileAsset::GetFont(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value argv[1];
    napi_value thisArg;

    napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr);
    if (argc < 1) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    auto *fontAsset = GetNativePtr<rive::FontAsset>(env, argv[0]);
    if (!fontAsset) {
        LOGE("Invalid FontAsset pointer");
        return nullptr;
    }

    auto font = fontAsset->font();
    napi_value result;
    napi_create_int64(env, reinterpret_cast<int64_t>(font.get()), &result);
    return result;
}

napi_value OhosFileAsset::CreateFont(napi_env env, napi_callback_info info)
{
    size_t argc = 2;
    napi_value argv[2];
    napi_value thisArg;

    napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr);
    if (argc < 2) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    int32_t rendererTypeIdx;
    napi_get_value_int32(env, argv[1], &rendererTypeIdx);

    // 直接使用 decodeAsset 模板函数
    auto font = decodeAsset<rive::Font>(env, argv[0], rendererTypeIdx);

    if (!font) {
        LOGE("Failed to decode font asset");
        return nullptr;
    }

    napi_value result;
    napi_status status = napi_create_int64(env, reinterpret_cast<int64_t>(font.release()), &result);
    if (status != napi_ok) {
        LOGE("Failed to create result value");
        return nullptr;
    }

    return result;
}

// ReleaseFont 实现
napi_value OhosFileAsset::ReleaseFont(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value argv[1];
    napi_value thisArg;

    napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr);
    if (argc < 1) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    int64_t ptrValue = 0;
    napi_status status = napi_get_value_int64(env, argv[0], &ptrValue);
    if (status != napi_ok || ptrValue == 0 || ptrValue == 0x9) {
        napi_value result;
        napi_get_undefined(env, &result);
        return result;
    }

    releaseAsset<rive::Font>(ptrValue);

    napi_value result;
    napi_get_undefined(env, &result);
    return result;
}

// AudioAsset 方法 (类似 FontAsset 的实现)
// SetAudio 实现
napi_value OhosFileAsset::SetAudio(napi_env env, napi_callback_info info)
{
    size_t argc = 2;
    napi_value argv[2];
    napi_value thisArg;

    napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr);
    if (argc < 2) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    auto *audioAsset = GetNativePtr<rive::AudioAsset>(env, argv[0]);
    auto *audioSource = GetNativePtr<rive::AudioSource>(env, argv[1]);

    if (!audioAsset || !audioSource) {
        LOGE("Invalid audio asset or audio source pointer");
        return nullptr;
    }

    audioAsset->audioSource(rive::ref_rcp(audioSource));

    napi_value result;
    napi_get_undefined(env, &result);
    return result;
}

// GetAudio 实现
napi_value OhosFileAsset::GetAudio(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value argv[1];
    napi_value thisArg;

    napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr);
    if (argc < 1) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    auto *audioAsset = GetNativePtr<rive::AudioAsset>(env, argv[0]);
    if (!audioAsset) {
        LOGE("Invalid AudioAsset pointer");
        return nullptr;
    }

    auto audioSource = audioAsset->audioSource();
    napi_value result;
    napi_create_int64(env, reinterpret_cast<int64_t>(audioSource.get()), &result);
    return result;
}

// CreateAudio 实现
napi_value OhosFileAsset::CreateAudio(napi_env env, napi_callback_info info)
{
    size_t argc = 2;
    napi_value argv[2];
    napi_value thisArg;

    napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr);
    if (argc < 2) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    int32_t rendererTypeIdx;
    napi_get_value_int32(env, argv[1], &rendererTypeIdx);

    // 对于音频创建，使用原始数据（允许音频系统窃取字节）
    auto audio = decodeAsset<rive::AudioSource>(env, argv[0], rendererTypeIdx);

    if (!audio) {
        LOGE("Failed to decode audio asset");
        return nullptr;
    }

    napi_value result;
    napi_status status = napi_create_int64(env, reinterpret_cast<int64_t>(audio.release()), &result);
    if (status != napi_ok) {
        LOGE("Failed to create result value");
        return nullptr;
    }

    return result;
}

napi_value OhosFileAsset::ReleaseAudio(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value argv[1];
    napi_value thisArg;

    napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr);
    if (argc < 1) {
        LOGE("Wrong number of arguments");
        return nullptr;
    }

    int64_t ptrValue = 0;
    napi_status status = napi_get_value_int64(env, argv[0], &ptrValue);
    if (status != napi_ok || ptrValue == 0 || ptrValue == 0x9) {
        napi_value result;
        napi_get_undefined(env, &result);
        return result;
    }

    releaseAsset<rive::AudioSource>(ptrValue);

    napi_value result;
    napi_get_undefined(env, &result);
    return result;
}

} // namespace ohos_rive